{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 同步抖动的AES能轨\n",
    "\n",
    "如果我们得到的内容不是那么的清晰，会发生什么呢？此时我们可以使用预处理模块。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "CRYPTO_TARGET = 'TINYAES128C'\n",
    "num_traces = 50\n",
    "CHECK_CORR = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 捕获抖动的轨迹\n",
    "\n",
    "### 生成新的硬件\n",
    "\n",
    "在文件`chipwhisperer/hardware/victims/firmware/simpleserial-aes/simpleserial-aes.c`可以找到如下：\n",
    "\n",
    "```c\n",
    "uint8_t get_pt(uint8_t* pt)\n",
    "{\n",
    "\ttrigger_high();\n",
    "\taes_indep_enc(pt); /* encrypting the data block */\n",
    "\ttrigger_low();\n",
    "\tsimpleserial_put('r', 16, pt);\n",
    "\treturn 0x00;\n",
    "}\n",
    "```\n",
    "我们给他加上一些随机延迟：\n",
    "\n",
    "```c\n",
    "uint8_t get_pt(uint8_t* pt)\n",
    "{\n",
    "\ttrigger_high();\n",
    "       for(volatile uint8_t k = 0; k < (*pt & 0x0F); k++);\n",
    "\taes_indep_enc(pt); /* encrypting the data block */\n",
    "\ttrigger_low();\n",
    "\tsimpleserial_put('r', 16, pt);\n",
    "\treturn 0x00;\n",
    "}\n",
    "```\n",
    "\n",
    "这种确定性的延迟并不是一个很好的选择，但是更加容易编写，因为我们并没有在这里链接使用CSPRNG。但是我们去除这些抖动并不依赖于这些特点，也就是说，对于使用其他的方式造成抖动，我们的方法也将起作用。\n",
    "\n",
    "**记得在后面删除这个函数以免破坏你的代码！**\n",
    "\n",
    "然后我们便可以开始构建代码了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../hardware/victims/firmware/simpleserial-aes\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2 EXTRA_OPTS=ADD_JITTER"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 设置\n",
    "\n",
    "继续，现在我们构建好了程序，确保你使用的是正确的文件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"Helper_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, time\n",
    "\n",
    "fw_path = '../hardware/victims/firmware/simpleserial-aes/simpleserial-aes-{}.hex'.format(PLATFORM)\n",
    "\n",
    "modtime = os.path.getmtime(fw_path)\n",
    "print(\"File build time: {:s} (built {:.2f} mins ago)\".format(str(time.ctime(modtime)), (time.time() - modtime)/60.0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此外，在我们捕获能轨之前，我们需要创建一个ChipWhisperer项目，因为分析器需要用到它们"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project = cw.create_project(\"projects/jittertime\", overwrite = True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 捕获能轨\n",
    "\n",
    "在接下来的循环中，每次将会加载一些新明文，指定示波器并且发送密钥和明文。最终记录将会返回一个新的轨迹到`traces[]`列表，最后，我们将其转换为numpy的数组，为了我们接下来的分析操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Capture Traces\n",
    "from tqdm import tnrange\n",
    "import numpy as np\n",
    "import time\n",
    "\n",
    "ktp = cw.ktp.Basic()\n",
    "\n",
    "\n",
    "for i in tnrange(num_traces, desc='Capturing traces'):\n",
    "    key, text = ktp.next()  # manual creation of a key, text pair can be substituted here\n",
    "    trace = cw.capture_trace(scope, target, text, key)\n",
    "    if trace is None:\n",
    "        continue\n",
    "    project.traces.append(trace)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Save project file\n",
    "project.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们现在对ChipWhisperer硬件的使用已经完成，所以我们可以断开连接了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# cleanup the connection to the target and scope\n",
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 分析\n",
    "\n",
    "为了修复抖动，我们需要将轨迹添加到预处理模块，我们可以奖我们的项目输入到`cwa.cpa()`中，但我们也可以直接在预处理模块中处理（稍后我们会提到）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "import chipwhisperer.analyzer as cwa\n",
    "project = cw.open_project(\"projects/jittertime\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后我们可以来绘制一些轨迹，你可以使用`range(10)`来调整绘制的范围，例如`range(1)`只会绘制第一条。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.io import output_notebook\n",
    "from bokeh.palettes import Dark2_5 as palette\n",
    "import itertools  \n",
    "\n",
    "output_notebook()\n",
    "p = figure(sizing_mode='scale_width', plot_height=300)\n",
    "\n",
    "# create a color iterator\n",
    "colors = itertools.cycle(palette)  \n",
    "\n",
    "x_range = range(0, len(project.waves[0]))\n",
    "for i, color in zip(range(5), colors): #Adjust range(n) to plot certain traces\n",
    "    p.line(x_range, project.waves[i], color=color)\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所以该如何修复呢，我们应该只绘制单条轨迹以便图片更加清晰，然后我们需要在图中找到一块特别的区域，例如在下面这个例子中，A是非常独特的区域，而B是有很多和它一样的区块的。\n",
    "\n",
    "![Resync example trace](img/resync_goodbad.png)\n",
    "\n",
    "我们将指定两项：\n",
    "1. 指定一块独特的区域。\n",
    "2. 我们将移动图像来搜索与之相符的匹配块。\n",
    "\n",
    "你可以通过下面的代码来定义`target_window`(目标窗口)和`max_shift`(最大偏移)。你可以尝试改变值直到找到符合条件的结果为止。也可以尝试一些不太行的例子，并且尝试绘制更多的轨迹直到找到符合条件的匹配为止。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "resync_traces = cwa.preprocessing.ResyncSAD(project)\n",
    "resync_traces.ref_trace = 0\n",
    "\n",
    "if PLATFORM == \"CWNANO\":\n",
    "    #Define a target window here. 500,900 for example is good based on above. But try some different values.\n",
    "    resync_traces.target_window = (300, 700)\n",
    "\n",
    "    # Define max_shift. Must not cause target_window to go outside of valid data. Try 16-600 range. Ideal value varies with how\n",
    "    # much jitter is in original data. \n",
    "    resync_traces.max_shift = 300\n",
    "elif PLATFORM == \"CWLITEXMEGA\" or PLATFORM == \"CW303\":\n",
    "    #Define a target window here. 500,900 for example is good based on above. But try some different values.\n",
    "    resync_traces.target_window = (1000, 1400)\n",
    "\n",
    "    # Define max_shift. Must not cause target_window to go outside of valid data. Try 16-600 range. Ideal value varies with how\n",
    "    # much jitter is in original data. \n",
    "    resync_traces.max_shift = 1000\n",
    "elif PLATFORM==\"CWLITEARM\":\n",
    "    #Define a target window here. 500,900 for example is good based on above. But try some different values.\n",
    "    resync_traces.target_window = (700, 1500)\n",
    "\n",
    "    # Define max_shift. Must not cause target_window to go outside of valid data. Try 16-600 range. Ideal value varies with how\n",
    "    # much jitter is in original data. \n",
    "    resync_traces.max_shift = 700\n",
    "\n",
    "#Uses objects from previous cells (plotting etc), so \n",
    "output_notebook()\n",
    "p = figure()\n",
    "new_proj = resync_traces.preprocess()\n",
    "\n",
    "for i, color in zip(range(0, 5), colors):\n",
    "    p.line(x_range, new_proj.waves[i], color=color)\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果他们执行完了，那么接下来继续攻击吧！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "leak_model = cwa.leakage_models.sbox_output\n",
    "attack = cwa.cpa(new_proj, leak_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后运行它："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cb = cwa.get_jupyter_callback(attack)\n",
    "attack_results = attack.run(cb, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你将会看见每个字节的PGE都到达了0，如果没有的话，你可能需要调整SAD值重新同步。你可能也需要增加捕获样本的长度。你可能会注意到它工作一会之后失败，这是因为之后的轨迹变的不是同步的了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 相关性绘制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.io import output_notebook\n",
    "\n",
    "attack_results = attack.results\n",
    "plot_data = cwa.analyzer_plots(attack_results)\n",
    "bnum = 0\n",
    "\n",
    "ret = plot_data.output_vs_time(bnum)\n",
    "\n",
    "output_notebook()\n",
    "p = figure()\n",
    "p.line(ret[0], ret[2], line_color='green')\n",
    "p.line(ret[0], ret[3], line_color='green')\n",
    "\n",
    "p.line(ret[0], ret[1], line_color='red')\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你应该看见一副包含红绿色的图，红色代表正确的子密钥第一个子节的相关性，其他的将是绿色。\n",
    "你应该看见两个或三个红色的尖峰，第一个是便是我们猜测子密钥进行S盒查询时发生的地方。（其余的来自AES的其他操作）\n",
    "\n",
    "其他的子密钥子节怎么处理呢？很简单，我们可以如下绘制它们："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rets = []\n",
    "for i in range(0, 16):\n",
    "    rets.append(plot_data.output_vs_time(i))\n",
    "\n",
    "p = figure()\n",
    "for ret in rets:\n",
    "    p.line(ret[0], ret[2], line_color='green')\n",
    "    p.line(ret[0], ret[3], line_color='green')\n",
    "    \n",
    "for ret in rets:\n",
    "    p.line(ret[0], ret[1], line_color='red')\n",
    "\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "真不错！你应该已经完成了如何重同步能轨数据，这是非常有用的工具，然后你将了解如何自定义一个类来扩展这些内容。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "key = list(project.keys[0])\n",
    "recv_key = [kguess[0][0] for kguess in attack_results.find_maximums()]\n",
    "assert key == recv_key, \"Failed to recover encryption key\\nGot: {}\\nExpected: {}\".format(recv_key, key)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert (attack_results.pge == [0]*16), \"PGE for some bytes not zero: {}\".format(attack_results.pge)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if CHECK_CORR:\n",
    "    max_corrs = [kguess[0][2] for kguess in attack_results.find_maximums()]\n",
    "    assert (np.all([corr > 0.75 for corr in max_corrs])), \"Low correlation in attack (corr <= 0.75): {}\".format(max_corrs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
